Skip to content
Go back

Inside a Low-Budget Spyware Operation

Introduction

In 2023, I stumbled across the control panel for a low-budget mobile spyware operation and found infrastructure held together by hardcoded credentials, weak operational security, and exposed victim data.

This post walks through how I found it, what the infrastructure revealed, how I monitored activity, and what the operation suggested about the actor behind it.

Why this mattered

Let’s rewind to the beginning. One rainy evening, I was hunting for adversary infrastructure with Shodan. Specifically, I was searching for interesting strings within web pages using the http.html: filter. After a lot of dead ends, I found four IPs running Node.js web servers on irregular ports.

Visiting the first server made it obvious what I had found: spyware. This particular panel did not appear to have many victims, but there were two visible infections, both belonging to women in Iran. victimo.png Clicking on the ‘Device’ name took me to the main section of the control panel, where various commands could be executed. Not all of these functions worked, which suggested the system was still under development. commands.png The victims were identified as being located in Iran based on the information periodically exfiltrated by the spyware, including SMS messages that featured the +98 area code. areacode.png

Digging Deeper

One of the first things I noticed was the use of WebSockets. Nothing unusual there. But inside bot-list.js, I found something more interesting: hardcoded credentials for the admin user. hard code.png At first, those credentials did not seem especially useful. But if they had hardcoded those values, what else might be buried in the code? ping.png After spending some time in the Network tab and reviewing the traffic, I noticed routine exfiltration over FTP using, unsurprisingly, hardcoded credentials. Remember the four separate IPs running the same spyware controller? Each one had its own credential set. ftp.png Once I logged into the server, I realized I had read and write access to every file and directory. More surprisingly, it was not just hosting spyware. It was also hosting several unrelated project websites. ftp-2.png I started tracing where victim data was being uploaded. Disturbingly, I found thousands of photos, messages, and call logs, some dating back years. PhotoExfil1.png Unsure whether the operator had noticed my login, I cloned the server with one important exception: I did not copy the directories containing victims’ personal photos and call logs. Pulling that material felt ethically wrong and would not have added anything useful to the technical analysis. I kept the rest locally so I could review the infrastructure if anything changed.

Wrapping Up

By reviewing the source code and connected domains, I was able to identify a possible owner of the domains, and potentially the server. Because of the risk of misattribution, I am not sharing those findings publicly.

Additional port scanning on the FTP server led me to a webpage that appeared to embed a live video feed, suggesting camera access. unnamed.png

Since I had write access to the www/public_html directory, I was theoretically able to upload my own PHP code. Given that, and the fact that the spyware controller required little to no authentication to access victims’ personal data, I opted to monitor the situation rather than push things further.

I was unable to determine the initial infection vector or how the victims were targeted. Given the small number of infections, all located in Iran, my assumption was that this was a small and likely targeted operation.

I needed a reliable way to track infections without repeatedly logging into the FTP server to download data. Since the C2 used WebSockets, I put together a small Go program to monitor activity. I do not have deep experience with either Go or WebSockets, but it worked well enough for the job.

Code on github

Throughout the period I spent monitoring the C2, I observed no new infections. However, I did notice they took down two of the servers and changed domains.

Final Notes

With only one spyware controller remaining and the exfiltration server still live, there was not much left to learn from continued passive monitoring alone. Pastedimage20250213152051.png While deleting data, I kept getting disconnected, likely because routine exfiltration activity was knocking out my session. I automated the re-login process with a simple Bash script and let it run for a while. Pasted image 20250213124438.png I also uploaded junk data that followed the existing naming convention in an attempt to create noise around the operator’s collection pipeline. Pasted image 20250213152255.png Not long after, my script started throwing errors. The reason turned out to be simple: the storage was full, although the server was still willing to accept zero-byte files that then appeared in the directory listing. Pasted image 20250213153744.png Pasted image 20250213153047.png

At that point, there was not much more I could do without crossing lines I did not want to cross. I still could not determine the initial infection method or what the victims had executed, but the infrastructure itself told a fairly clear story about the operator’s tradecraft.

Responsible Disclosure

I disclosed what I found to the FBI. As far as I am aware, no action was taken.


Share this post on:

Previous Post
Shipping ClipShield, a Browser Extension That Blocks ClickFix and Clipboard Attacks
Next Post
How I found an infinite money bug in a rewards platform